/*
 * Hus_Button.h
 *
 *  Created on: 2020.7.16
 *      Author: HpDadi
 */
 
/*使用方法：
 *1.在cubeMX里配置uart的采用DMA接收，DMA里配置以字节形式循环接收；
 *2.按照初始化的例子建立全局结构体变量；如果只使用Hus_Uart_Rx_DMABufferRead读取只需要建立Hus_Uart_Rx_DMABufferStruct结构体的全局变量；
 *3.在主函数之前运行Hus_Uart_Rx_DMABufferStart；
 *4.如果需要按头尾提取信息的方式的到信息，需创建任务，入口函数为Hus_Uart_Rx_DMAextrImTask；
 *5.提取的信息会以回调函数的方式返回，回调函数以阻塞信息提取的方式处理信息。回调函数为__weak，默认串口输出信息。
 *注意：缓存区要大于接收的信息，否则会出错。
 */
/*initial example:

static uint8_t recebuffer[100];
static uint8_t tmpData[100];
static uint8_t imData[100];
Hus_Uart_Rx_DMABufferStruct husUartRxDMABufferStruct={
  &huart1,   //
  recebuffer,
  100
};
Hus_Uart_Rx_DMAextrImStruct husUartRxDMAextrImStruct={
  &husUartRxDMABufferStruct,
  tmpData,//uint8_t* pData;
  100,   // uint16_t dataSize;
  imData,  //uint8_t* pIm;
  100,  //uint16_t imSize;
  '{', //char starter;
  '}',  //char ender;
  20     //uint8_t DelayTime;
};

*/


#include "Hus_Uart_Rx.h"
#include "string.h"

__weak void Hus_Uart_Rx_DMAextrImHook(Hus_Uart_Rx_DMABufferStruct* husUartRxDMABufferStruct, uint8_t* pIm, uint16_t imnum)
{
  //do somethin here;
  HAL_UART_Transmit(husUartRxDMABufferStruct->huart,pIm,imnum,20);
  
}

__weak void Hus_Uart_Rx_DMAextrImErrorHook(Hus_Uart_Rx_DMABufferStruct* husUartRxDMABufferStruct, uint8_t* pIm, uint16_t imnum)
{
  //if you want to handle full error
  //char* imerror = "error full"
  //HAL_UART_Transmit(husUartRxDMABufferStruct->huart,imerror,strlen(imerror),20);
  //HAL_UART_Transmit(husUartRxDMABufferStruct->huart,pIm,imnum,20);

}

void Hus_Uart_Rx_DMABufferStart(Hus_Uart_Rx_DMABufferStruct* husUartRxDMABufferStruct)
{
    HAL_UART_Receive_DMA(husUartRxDMABufferStruct->huart,husUartRxDMABufferStruct->pBuffer,husUartRxDMABufferStruct->Size);
}


uint16_t Hus_Uart_Rx_DMABufferRead(Hus_Uart_Rx_DMABufferStruct* husUartRxDMABufferStruct,uint8_t* pData,uint16_t dataSize)
{
  uint8_t* pBuffer = husUartRxDMABufferStruct->pBuffer;
  uint8_t pReaderOffset = husUartRxDMABufferStruct->pReaderOffset;
  uint8_t size = husUartRxDMABufferStruct->Size;
  uint16_t pWriterOffset;
  uint16_t pDMAoffset;
  uint16_t DMAcounter;
  DMAcounter =__HAL_DMA_GET_COUNTER(husUartRxDMABufferStruct->huart->hdmarx);
  pDMAoffset = size - DMAcounter;
  
  for(pWriterOffset = 0; pWriterOffset<dataSize; pWriterOffset++)
  {
    if(pReaderOffset != pDMAoffset){
      *(pData+pWriterOffset) = *(pBuffer+pReaderOffset);
    }else{
      break;
    }
    ++pReaderOffset;
    if(pReaderOffset>=size){
      pReaderOffset = 0;
    }
  }
  husUartRxDMABufferStruct->pReaderOffset = pReaderOffset;
  return pWriterOffset;
}

void Hus_Uart_Rx_DMAextrImTask(void* pvParameters)
{
  Hus_Uart_Rx_DMAextrImStruct* husUartRxDMAextrImStruct = (Hus_Uart_Rx_DMAextrImStruct*) pvParameters;
  
  Hus_Uart_Rx_DMABufferStruct* husUartRxDMABufferStruct= husUartRxDMAextrImStruct->husUartRxDMABufferStruct;
  uint8_t* pData = husUartRxDMAextrImStruct->pData;
  uint16_t dataSize = husUartRxDMAextrImStruct ->dataSize;
  uint8_t* pIm = husUartRxDMAextrImStruct ->pIm;
  uint16_t imSize = husUartRxDMAextrImStruct ->imSize;
  char starter = husUartRxDMAextrImStruct ->starter;
  char ender = husUartRxDMAextrImStruct ->ender;
  uint8_t DelayTime =husUartRxDMAextrImStruct ->DelayTime;
  
  uint32_t xLastWakeTime;
  
  memset(pData,0,dataSize);
  uint16_t nums;
  uint16_t i;
  uint16_t numOfMark;
  uint16_t imnum;
  char* pp = "error";
  for(;;)
  {
    xLastWakeTime = osKernelGetTickCount();
    
    
    memset(pData,0,dataSize);
    nums = Hus_Uart_Rx_DMABufferRead(husUartRxDMABufferStruct,pData,dataSize);
    //HAL_UART_Transmit(husUartRxDMABufferStruct->huart,pData,nums,50);
    if(nums !=0){
      for(i =0;i<nums; i++){
        //error imSize is too small
        if(imnum>=imSize){
        //hander_error if you need!
        Hus_Uart_Rx_DMAextrImHook(husUartRxDMABufferStruct,pIm,imnum);
          memset(pIm,0,imSize);
          imnum = 0;
          numOfMark = 0;
          break;
        }
        if (*(pData+i) == starter){
          if (numOfMark == 0){
            memset(pIm,0,imSize);
          }
          numOfMark++;
          *(pIm+imnum) = starter;
          ++imnum;
          continue;
        }
        
        if (*(pData+i) == ender){
          if (numOfMark>=1){
            *(pIm+imnum) = ender;
            ++imnum;
            numOfMark--;
            if(numOfMark == 0){
              //***************
              Hus_Uart_Rx_DMAextrImHook(husUartRxDMABufferStruct,pIm,imnum);
              //****************
              memset(pIm,0,imSize);
              imnum = 0;
              numOfMark = 0;
            } 
          }
          continue;
        }
        
        if(numOfMark >=1){
          *(pIm+imnum) = *(pData+i);
          imnum++;
          continue;
        }
      }
    }
    
    
    
    osDelayUntil(xLastWakeTime + pdMS_TO_TICKS(DelayTime));//pdMS_TO_TICKS seems not a CMSIS micro;
  }
}
  
